package Railroad.Communication.USB;

import Railroad.Communication.CommData;
import Railroad.Communication.CommDriver;
import ch.ntb.usb.LibusbJava;
import ch.ntb.usb.Usb_Bus;
import ch.ntb.usb.Usb_Device;

public class CommDriverUSB implements CommDriver {
    private static final int vendorId = 0x03EB;
    private static final int productId = 0x6126;
    private static final int endpointIn = 0x82;
    private static final int endpointOut = 0x01;
    private long usbDevice = 0;
    private static boolean initialized = false;
    
    private boolean connected = false;
   
    
    public CommDriverUSB() {
        initialize();
    }

    @Override
    public boolean connect() {
        if ((usbDevice = FindDevice()) != 0) {
            LibusbJava.usb_set_configuration(usbDevice, 1);
            int claimed = LibusbJava.usb_claim_interface(usbDevice, 0);
            if (claimed >= 0)
                connected = true;
            else
                usbDevice = 0;
        }
        if (!connected)
            System.out.println("Nepodarilo sa pripojit na USB zariadenie.");
        return connected;
    }
    
    private void initialize() {
        if (initialized)
            return;
        
        LibusbJava.usb_init();
        LibusbJava.usb_find_busses();
        LibusbJava.usb_find_devices();
        initialized = true;
    }
    
    private static long FindDevice() {
        Usb_Bus bus = LibusbJava.usb_get_busses();
        while (bus != null) {
            Usb_Device device = bus.getRootDev();
            while (device != null) {
                if (device.getDescriptor().getIdVendor() == vendorId &&
                    device.getDescriptor().getIdProduct() == productId)
                {
                    return LibusbJava.usb_open(device);
                }
                device = device.getNext();
            }
            bus = bus.getNext();
        }
        return 0;
    }

    @Override
    public void disconnect() {
        if (isConnected())
            LibusbJava.usb_close(usbDevice);
        connected = false;
    }
    
    @Override
    public boolean isConnected() {
        return connected;
    }

    @Override
    public void send(CommData data) {
        LibusbJava.usb_bulk_write(usbDevice, endpointOut, data.toArray(), data.size(), 1000);
    }

    @Override
    public CommData receive(int length) {
        byte[] received = new byte[length];
        LibusbJava.usb_bulk_read(usbDevice, endpointIn, received, length, 1000);
        return new CommData(received);
    }
    
}
